package com.sbr.seb.rule.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sbr.seb.rule.Businessable;
import com.sbr.seb.rule.Specification;
import com.sbr.seb.rule.annotation.ISpecification;
import com.sbr.seb.rule.exception.SpecificationException;

@Aspect
public class BusinessSpecificationAspect {

	private static final Logger logger = LoggerFactory.getLogger(BusinessSpecificationAspect.class);


	@SuppressWarnings("unchecked")
	@Before("@annotation(com.sbr.seb.rule.annotation.ISpecification)")
	public <T> void execMethodeSM(final JoinPoint pjp) throws Throwable {
		try {
			logger.debug("checking specifications");
			Object target = pjp.getTarget();
			final T[] arguments = (T[]) pjp.getArgs();
			Collection<? extends Specification<T>> specList = null;
			if (target instanceof Businessable<?>) {

				final Businessable<T> sm = (Businessable<T>) pjp.getTarget();
				logger.debug("sm = "+sm);

				specList = sm.getSpecifications();
				logger.debug("specifications liste "+sm.getSpecifications());
			} else {
				Method invoked = getMethod(pjp);
				ISpecification annotation = invoked.getAnnotation(ISpecification.class);
				
//				if (annotation.value().length > 0) {
//					List<Class<? extends Specification<?>>> classSpecList = Arrays.asList(annotation.value());
//					specList = new ArrayList<? extends Specification<T>>();
//					for (Class<? extends Specification<?>> classSpec : classSpecList) {
//						
//					}
//				}
			}


			for (Specification<T> specification : specList) {
				logger.debug("specification = "+specification);
				logger.debug("specification is "+specification.isSatisfiedBy(arguments[0]));
				if (!specification.isSatisfiedBy(arguments[0])) {
					throw new SpecificationException("BOUH !");
				}
			}
		} catch (Exception e) {
			if (e instanceof SpecificationException) {
				throw e;
			}
			logger.error("ERROR ",e);
		}

	}


	@SuppressWarnings("unchecked")
	protected Method getMethod(JoinPoint jp) {
		MethodSignature met = (MethodSignature) jp.getSignature();
		try {
			Method method = jp.getSourceLocation().getWithinType().getMethod(
					met.getMethod().getName(),
					met.getMethod().getParameterTypes());
			method.setAccessible(true);
			return method;
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
	}
}